﻿/********************************************************************
	author:		tianchunhua
	created:	2010/12/17	
	purpose:	将数据发送至网络接口，并接收数据
*********************************************************************/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;

namespace Skyray.Net
{
    /// <summary>
    /// 网络传输接口
    /// </summary>
    public class LanTransPort
    {
        /// <summary>
        /// CTOR
        /// </summary>
        public LanTransPort()
        {
            _lanInterface.ConnectstatusChangedEvent += delegate(LanTransState reason)
            {
                //数据连接异常时处理
                if (LanstatusChangedEvent != null)
                {
                    LanstatusChangedEvent(reason);
                }
            };
            _lanInterface.DataReceiveCallBack = delegate(byte[] buf)
            {
                // 向上层转发数据
                if (OnDataReceive != null)
                {
                    OnDataReceive(buf);
                }
            };
        }
        /// <summary>
        /// 传输队列，传输成功时数据出队列
        /// </summary>
        private Threaded.TQueue<byte[]> _talkQueue = new Threaded.TQueue<byte[]>(10);

        /// <summary>
        /// 底层串口，进行了转义发送
        /// </summary>
        private LanInterface _lanInterface = new LanInterface();

        /// <summary>
        /// 传输线程
        /// </summary>
        private Thread _thrTransport;

        /// <summary>
        /// 传输线程结束标记
        /// </summary>
        private bool _Exit;

        /// <summary>
        /// 日志记录
        /// </summary>
        private readonly log4net.ILog _log = log4net.LogManager.GetLogger(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType);

        /// <summary>
        /// 数据反馈
        /// </summary>
        /// <param name="buf">接收数据缓存</param>
        public delegate void DataReceiveCallback(Byte[] buf);

        /// <summary>
        /// 委托，正确收到一次应答传输时触发 
        /// </summary>
        public DataReceiveCallback OnDataReceive = null;

        /// <summary>
        /// 网络连接状态处理
        /// </summary>
        public LanstatusChangedEventHandler LanstatusChangedEvent;
        /// <summary>
        /// 判定程序是否已经连接
        /// </summary>
        public bool IsConnect
        {
            get
            {
                return _lanInterface.IsStartUp;
            }
        }

        /// <summary>
        /// 开始一次数据传输
        /// </summary>
        /// <param name="buf"> 数据 </param>
        public void Talk(Byte[] buf)
        {
            _talkQueue.Enqueue(buf);
        }

        /// <summary>
        /// 现有待传数据
        /// </summary>
        public int WaitingDataCount
        {
            get
            {
                return _talkQueue.Count;
            }
        }

        /// <summary>
        /// 清除数据
        /// </summary>
        private void Clear()
        {
            //清空队列
            _talkQueue.Clear();
        }

        /// <summary>
        /// 断开连接
        /// </summary>
        public void DisConnect()
        {
            Console.WriteLine(DateTime.Now.ToString() + "\tClose......");
            _Exit = true;
            if (_thrTransport != null)
                _thrTransport.Join(200);
            //等待线程自动退出
            _lanInterface.ShutDown();

            //清空数据
            _talkQueue.Clear();
            Console.WriteLine("LanTransPort Shutdown");
        }

        /// <summary>
        /// 连接服务器
        /// </summary>
        /// <param name="IpAdress">IP地址</param>
        /// <param name="port">端口号</param>
        public void Connect(string IpAdress, int port)
        {
            Console.WriteLine(DateTime.Now.ToString() + "\tConnect......");

            DisConnect();
            //清空数据
            _talkQueue.Clear();

            //连接设备  
            if (_lanInterface.Connect(IpAdress, port))
            {
                _Exit = false;
                _thrTransport = new Thread(TransportFunc) { Name = "TransportFunc", IsBackground = true };
                _thrTransport.Start();
            }
            else
            {
                _Exit = true;
            }
            Console.WriteLine("LanTansPort Connected.");
            return;
        }

        #region 数据校验
        /// <summary>
        /// 生成带CRC校验位的数组  CRC=X8+X5+X4+1  
        /// </summary>
        /// <param name="buffer"></param>
        /// <returns></returns>
        public byte[] GetCRC8(byte[] buffer)
        {
            byte crc, i, j;
            crc = 0;

            for (j = 0; j < buffer.Length; j++)
            {
                for (i = 0x01; i != 0; i <<= 1)
                {
                    if (((crc & 0x01) ^ (buffer[j] & i)) == 1)
                    {
                        crc ^= 0x18;
                        crc >>= 1;
                        crc |= 0x80;
                    }
                    else
                        crc = (byte)(crc >> 1);
                }
            }
            buffer[buffer.Length - 1] = crc;
            return buffer;
        }

        /// <summary>
        /// 验证CRC校验
        /// </summary>
        /// <param name="buffer"></param>
        /// <returns></returns>
        public bool CRCCheck(byte[] buffer)
        {
            byte crc, i, j;
            crc = 0;

            for (j = 0; j < buffer.Length; j++)
            {
                for (i = 0x01; i != 0; i <<= 1)
                {
                    if (((crc & 0x01) ^ (buffer[j] & i)) == 1)
                    {
                        crc ^= 0x18;
                        crc >>= 1;
                        crc |= 0x80;
                    }
                    else
                        crc = (byte)(crc >> 1);
                }
            }
            return (crc == 0);
        }
        #endregion

        /// <summary>
        /// 传输线程函数
        /// </summary>
        private void TransportFunc()
        {
            _log.Debug(String.Format("exit = {0}", _Exit));
            while (!_Exit)
            {
                if (_talkQueue.Count <= 0)
                {
                    Thread.Sleep(50);
                    // 没有数据
                    continue;
                }
                // 取出传输队列头的数据，为了出错后重传，数据不出队列
                Byte[] sendBuf = _talkQueue.Dequeue();

                // 打包发送               
                _lanInterface.Write(sendBuf);

                Thread.Sleep(10);//延时作切换
            }
        }

    }
}
